// 基于axios封装网络请求
// 每个程序员的想法都一样，封装的地方和名字都不一样，但是思路相同
import theaxios from 'axios'
import router from '@/router'
import { Notify } from 'vant'
import { getToken, removeToken } from '@/utils/token.js' // setToken
// import { updateTokenAPI } from '@/api'
const axios = theaxios.create({
  baseURL: 'http://toutiao.itheima.net',
  timeout: 20000 // 20秒超时时间(请求20秒无响应直接判定超时)
})

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  // console.log(config)
  // 目标：统一携带token
  // 判断本地有token再携带，判断具体api/index.js它的里面如果没有携带Authorization，我再添加上去
  // 未定义叫undefined，null具体的值你得赋予才叫空
  // ?.叫做可选链操作符。如果前面对象里没有length属性，整个表达式就会在原地返回undefined。如果getToken()在原地有值token字符串，才能调用length获取长度。  防止报错
  if (getToken()?.length > 0 && config.headers.Authorization === undefined) {
    config.headers.Authorization = `Bearer ${getToken()}`
  }
  return config
}, async function (error) {
  // 对请求错误做些什么
  return Promise.reject(error)
})

// 添加响应拦截器
// 拦截器：本质就是一个函数
axios.interceptors.response.use(function (response) {
  // 2xx 3xx 范围内的状态码都会触发该函数。
  // 对响应数据做点什么
  return response
}, async function (error) {
  // 超出 2xx 范围的状态码都会触发该函数。
  // 对响应错误做点什么
  // console.dir(error)
  // 只有401才代表身份过期，才需要跳转登录
  if (error.response.status === 401) {
    // 有个坑：不能使用this.$router。this指向问题-因为this不是vue组件对象无法调用$router
    // 解决：this.$router为了拿到router路由对象，所以直接去上面引入@/router下router对象
    Notify({ type: 'warning', message: '身份已过期！' })
    removeToken()
    // 方式1：强制跳转登录页，用户有感知
    // 先清除token，才能让路由守卫判断失效。放行我去登录页(被动退出)
    // router.currentRoute 相当于在 .vue(比如index.vue)文件内this.$route拿到当前路由对象信息
    // fullPath，路由对象里完整路由路径(#后面的一切)
    router.replace(`/login?path=${router.currentRoute.fullPath}`)
  }
  // 方式2：使用refresh_token来换回新的token再继续使用，js代码实现，用户无感知，效果好
  // const res = await updateTokenAPI()
  // 新的token回来之后，我们要做什么
  // 1、更新token在本地
  // setToken(res.data.data.token)
  // 2、更新新的token在请求头里
  // error.config.headers.Authorization = `Bearer ${res.data.data.token}`
  // 3、未完成这次请求，再次发起刚才报错的这次请求
  // error.config就是上一次请求的配置对象
  // 结果我们要return回原本逻辑页面调用的地方
  //   return axios(error.config)
  // } else if (error.response.status === 500 && error.config.url === '/v1_0/authorizations' && error.config.method === 'put') {
  //   // 刷新的refresh_token也过期了
  //   localStorage.clear() // 清除本地所有的值
  //   Notify({ type: 'warning', message: '身份已过期！' })
  //   router.replace('/login')
  // }
  return Promise.reject(error)
})
// 目标：token讲解
// 1、手动修改localStorage里面的token，让他过期
// 2、点击反馈或者其他需要表明身份的接口(错误token携带给后台请求)
// 3、反馈不敢兴趣，这次请求返回状态为401，进入错误响应拦截器
// 解决401问题：
// 方式1：清除token，强制跳转登录页，让用户有感知的重新登录，拿到新的token存入本地(替换到本地)
// 需要重新点击反馈按钮，再次反馈，这种感觉特别不好
// 方式2：刷新token，使用登录时保存的refresh_token，调用另一个接口，来换回新的token替换到本地，再次完成本次未完成的请求，这种感觉，用户无感知，体验好(js代码实现)
// 1、登录页面，localStorage.setItem('refresh_token'，存入refresh_token)
// 2、在401中注释掉跳转login的代码，引入刷新token的接口方法调用
// 3、替换保存到本地新的token
// 4、error对象里headers也替换成新的token
// 5、axios再次发起这次未完成的请求，返回Promise对象到最开始的逻辑页面

export default ({ url, method = 'GET', params = {}, data = {}, headers = {} }) => {
  // 上面括号的等号右边是解构赋值之后的默认值写法(也就是说，如果外面不传method, params, data, headers，我就给他一个默认值，就是等号右边的东西)
  // axios请求之后会在原地留下一个promise对象，要return出去
  return axios({
    url,
    method,
    params,
    data,
    headers
  })
  // 如果用jquery
  // return new Promise((resolve, reject) => {
  // 判断如果param有值，需要自己写js代码，把params对象里的key和value拼接到url上
  //   $.ajax({
  //     url,
  //     data,
  //     headers,
  //     type: method,
  //     success:(res)=>{
  //     resolve(res)
  // },
  //     error:err=>{
  //     reject(err)
  // }
  //   })
  // })
}
// 但是上面有局限
// 导出的axios方法在使用时
/*
// 我在逻辑页面调用时，传入的是这5个配置的名字
     axios({
     url:'请求地址',
     method:'请求方式',
     params:{},
     data: {},
     headers: {}
     })
 */
// 问题来了：万一将来我要更新request.js里封装网络请求的工具
// 把axios换成jquery的$.ajax
// improt $ from 'jquery'
// export default $.ajax
/*
   $.ajax({
     url:'请求地址',
     type:'请求方式',
     data: {}, 没有params
     headers: {}
     })
 */
